package com.fyyg.wechat.util;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;


public class TokenInterceptor implements HandlerInterceptor {
	private static final Log log=LogFactory.getLog(TokenInterceptor.class);
	public static String TOKEN_SESSION="tokenSession";
	
	/** 验证Token **/
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
			Object handler) throws Exception {
		 String token=getRequestToke(request);//获取请求参数里面的Token	 
		 String type=request.getParameter("toKenType");//true 表示异步消息提示  否则页面消息提示
		 if(StringUtils.isEmpty(type)){
			 type="true";
		 }
		 
		 Token annotation=null;
		 //强制方式 
		 if (handler instanceof HandlerMethod ) {
	            HandlerMethod handlerMethod = (HandlerMethod) handler;
	            Method method = handlerMethod.getMethod();	
	            annotation = method.getAnnotation(Token.class);
	            if (annotation != null) {
	                boolean saveSession = annotation.save();
	                if (saveSession) {
	                	generateToken(request); //生成Token保存到Session
	                }
	                
	                boolean removeSession = annotation.remove();
	                if (removeSession) {
	                    if (! validateToken(request, token)) {//等于false表示验证失败
	                    	if(StringUtils.isEmpty(token)){
	                    		 request.setAttribute("messageContxt", "请勿非法操作");
		        			     request.setAttribute("messageLink", "index/shouye.jhtml");
		        			     request.setAttribute("messageLinkName", "返回首页");
		        					request.getRequestDispatcher("/v2/user/backmessage").forward(request, response);
		        				 return false;
	                    	}else if(!type.equals("true")){
	                    		 request.setAttribute("messageContxt", "您的表单已提交，请勿重复提交");
		        			     request.setAttribute("messageLink", "index/shouye.jhtml");
		        			     request.setAttribute("messageLinkName", "返回首页");
		        					request.getRequestDispatcher("/v2/user/backmessage").forward(request, response);
		        				 return false;
	                    	}else{
	                    		
	                    		 String typeapp=request.getParameter("type");//true 表示异步消息提示  否则页面消息提示
	                    		 if(typeapp!=null && typeapp.equals("app")){
	                    			 return true;
	                    		 }
	                    		 response.getWriter().write("{\"msg\":\"您的表单已提交，请勿重复提交\",\"token\":\"\"}");
	                    		return false;
	                    		 
	                    	}
	                       
	                    }
	                }
	            }
	      }
		 
		  //可选方式
		  if(annotation==null){
       		  if(! StringUtils.isEmpty(token)){ 
       			 if(! validateToken(request, token)){//等于false表示验证失败
       				if(!type.equals("true")){
	       				 request.setAttribute("messageContxt", "您的表单已提交，请勿重复提交");
	       			     request.setAttribute("messageLink", "index/shouye.jhtml");
	       			     request.setAttribute("messageLinkName", "返回首页");
        					request.getRequestDispatcher("/v2/user/backmessage").forward(request, response);
	       			     return false;	
       				}else{
                		response.getWriter().write("{\"msg\":\"表单已提交，请勿重复提交！\",\"token\":\"\"}"); 
                		return false;
                		 
                	}
       			 }
       		  }
		  }
		   
		  return true;
	}
	
	public static String createToken(HttpServletRequest request) {
		new TokenInterceptor().generateToken(request);
		String token=(String)request.getSession().getAttribute(TokenInterceptor.TOKEN_SESSION);
		return token;
	}
	
	
	/** 生成Token保存到Session **/
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response,
			Object obj, ModelAndView view) throws Exception {
		generateToken(request);
	}

	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object obj, Exception e)throws Exception {
		
	}
	
	/**生成token**/
	public void generateToken(HttpServletRequest request){
		 HttpSession session=request.getSession();
		 //获取Session里面的Token
		 String token=(String)session.getAttribute(TOKEN_SESSION);
		 if(StringUtils.isEmpty(token)){ 
			 //使用UUID生成新的Token
			 token= UUID.randomUUID().toString();
			 session.setAttribute(TOKEN_SESSION,token);
		 }
	}
	
	/** 获取请求参数里面的Token **/
	private String getRequestToke(HttpServletRequest request) {
		//接口排除token验证
		if(request.getServletPath().indexOf("/api") != -1){
			return null;
		}
		Map params = request.getParameterMap();
        if (!params.containsKey("token")) {
            return null;
        }
        
        String[] tokens = (String[]) params.get("token");
        if ((tokens == null) || (tokens.length < 1)) {
        	log.warn("获取令牌名称为空或为NULL");
            return null;
        }
        return tokens[0];
	}
	
	/** 验证Token **/
	private boolean validateToken(HttpServletRequest request,String token) {
		
		//移动端跳过验证
		String sign=request.getParameter("sign");
		if(sign!=null && !sign.equals("") && sign.length()==32){
			return true;
		}
		//客户端token
        if (StringUtils.isEmpty(token)) {
        	log.warn("客户端令牌是无效的!sessionToken为空");
            return false;
        }
        
        //服务器端token
        HttpSession session=request.getSession();
        //获取Session里面的Token
		String sessionToken=(String)session.getAttribute(TOKEN_SESSION);
		if(StringUtils.isEmpty(sessionToken)){
			log.warn("服务器端令牌是无效的!sessionToken为空");
			return false;
		}
		
		token=token.replace('_', '-');
		
		//取出Session里面保存的Token与页面请求参数里面的Token进行比较 
		if(! sessionToken.equals(token)){
			log.warn("令牌是无效的!token:"+ token +"、sessionToken:"+ sessionToken);
			return false;
		}
		
        //移除Token  
		session.removeAttribute(TOKEN_SESSION);
        return true;
	}

}
